import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
import { ResultEnum } from '@/global/constant'

interface RequestInterceptors<T = AxiosResponse> {
	requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
	requestInterceptorCatch?: (error: any) => any
	responseInterceptor?: (res: T) => T
	responseInterceptorCatch?: (error: any) => any
}

interface HTTPRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
	interceptors?: RequestInterceptors<T>
	showLoading?: boolean
}

interface IResultDataType {
	code: number
	msg: string
	[key: string]: any
}

const DEFAULT_LOADING = false

class Request {
	instance: AxiosInstance
	interceptors?: RequestInterceptors
	showLoading: boolean
	loading?: any

	constructor(config: HTTPRequestConfig) {
		this.instance = axios.create(config)
		this.showLoading = config.showLoading ?? DEFAULT_LOADING
		this.interceptors = config.interceptors

		// 每个实例单独添加的拦截器
		this.instance.interceptors.request.use(
			this.interceptors?.requestInterceptor,
			this.interceptors?.requestInterceptorCatch
		)
		this.instance.interceptors.response.use(
			this.interceptors?.responseInterceptor,
			this.interceptors?.responseInterceptorCatch
		)

		// 添加全局拦截器
		this.instance.interceptors.request.use(
			(config) => {
				return config
			},
			(err) => {
				return err
			}
		)

		this.instance.interceptors.response.use(
			({ data }) => {
				this.loading?.close()
				if (data.code == ResultEnum.SUCCESS) {
					return data.data
				} else if (data.code == ResultEnum.OUTOFDATE) {
					return Promise.reject(new Error(data.msg))
				} else {
					return Promise.reject(new Error(data.msg))
				}
			},
			(err) => {
				this.loading?.close()
				console.log(err)
				return err
			}
		)
	}

	request<T>(config: HTTPRequestConfig<T>): Promise<T> {
		if (config.interceptors?.requestInterceptor) {
			config = config.interceptors.requestInterceptor(config)
		}
		if (config.showLoading === true) {
			this.showLoading = config.showLoading
		}
		return new Promise((resolve) => {
			this.instance
				.request<any, T>(config)
				.then((res) => {
					if (config.interceptors?.responseInterceptor) {
						res = config.interceptors.responseInterceptor(res)
					}
					this.showLoading = DEFAULT_LOADING
					resolve(res)
				})
				.catch(() => {
					this.showLoading = DEFAULT_LOADING
					// reject(err)
					// console.log(err)
				})
		})
	}

	get<T = IResultDataType>(config: HTTPRequestConfig<T>): Promise<T> {
		clearNullValue('params', config)
		return this.request<T>({ method: 'GET', ...config })
	}
	post<T = IResultDataType>(config: HTTPRequestConfig<T>): Promise<T> {
		clearNullValue('data', config)
		return this.request<T>({ method: 'POST', ...config })
	}
	delete<T = IResultDataType>(config: HTTPRequestConfig<T>): Promise<T> {
		return this.request<T>({ method: 'DELETE', ...config })
	}
	patch<T = IResultDataType>(config: HTTPRequestConfig<T>): Promise<T> {
		return this.request<T>({ method: 'PATCH', ...config })
	}
}

// 检查并清除空值的请求参数
function clearNullValue(configKey: string, config: any): void {
	const keys = Object.keys(config[configKey] ?? {})
	if (keys.length)
		for (const key of keys) {
			const value = config[configKey][key]
			if (value === undefined || value === null || value == '') {
				delete config[configKey][key]
			}
		}
}

export default Request
